package com.service.base.generator.app.web;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.service.base.generator.app.config.MySqlTypeConvertExt;
import com.service.base.generator.app.dao.DbConfigDao;
import com.service.base.generator.app.dao.TableStrategyConfigDao;
import com.service.base.generator.app.model.ColumnInfo;
import com.service.base.generator.app.model.DbConfig;
import com.service.base.generator.app.model.TableInfo;
import com.service.base.generator.app.model.TableStrategyConfig;
import com.service.base.generator.app.service.DbTableInfoService;
import com.service.base.generator.gencore.AutoGenerator;
import com.service.base.generator.gencore.InjectionConfig;
import com.service.base.generator.gencore.common.StringPool;
import com.service.base.generator.gencore.common.io.FileUtils;
import com.service.base.generator.gencore.common.io.ZipFileUtils;
import com.service.base.generator.gencore.dbconfig.config.*;
import com.service.base.generator.gencore.dbconfig.rules.NamingStrategy;
import com.service.base.generator.gencore.genconfig.GlobalConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.zip.ZipOutputStream;


/**
 * @author wangyongkun
 * @create 2020/12/13
 */
@Slf4j
@Controller
@RequestMapping
public class GenCodeController extends BaseController {

    @Autowired
    private DbTableInfoService tableInfoService;

    @Autowired
    private DbConfigDao dbConfigDao;

    @Autowired
    private TableStrategyConfigDao tableStrategyConfigDao;

    @RequestMapping("/index")
    public String init() {
        if (request.getSession().getAttribute("user") == null) {
            return "redirect:/login";
        }
        return "/views/index/index";
    }

    @GetMapping("/getDbList")
    @ResponseBody
    public JSONObject getDbList(Model model) {
        List<DbConfig> dbConfigList = dbConfigDao.findAll();
        return respJson(0, null, dbConfigList);
    }

    @GetMapping("/getByDbId")
    @ResponseBody
    public JSONObject getByDbId(Long id) throws IOException {
        DbConfig dbConfig = dbConfigDao.getOne(id);
        return respJson(0, "", dbConfig);
    }

    /**
     * 显示Table列表
     */
    @RequestMapping(value = "/database-list", method = RequestMethod.GET)
    public String databaseList(Model model, DbConfig dbConfig) {
        return "/views/db/database_list";
    }

    /**
     * 显示Table列表
     */
    @RequestMapping(value = "/edit", method = RequestMethod.PUT)
    @ResponseBody
    public JSONObject edit(@RequestBody DbConfig dbConfig) {
        dbConfigDao.save(dbConfig);
        return respJson(0, "修改成功", true);
    }

    /**
     * 测试数据库配置
     */
    @ResponseBody
    @RequestMapping(value = "/test", method = RequestMethod.POST)
    public JSONObject test(DbConfig dbConfig) {
        String result = tableInfoService.testConnection(dbConfig);
        if (StringUtils.isEmpty(result)) {
            return respJson(0, "测试成功", result);
        } else {
            return respJson(1, "数据库链接失败", result);
        }
    }

    /**
     * 显示Table列表
     */
    @RequestMapping(value = "/save", method = RequestMethod.POST)
    @ResponseBody
    public JSONObject save(@RequestBody DbConfig dbConfig) {
        dbConfigDao.save(dbConfig);
        return respJson(0, "添加成功", true);
    }

    /**
     * 显示Table列表
     */
    @RequestMapping(value = "/delete", method = RequestMethod.GET)
    @ResponseBody
    public JSONObject delete(Model model, DbConfig dbConfig) {
        dbConfigDao.deleteById(dbConfig.getId());
        return respJson(0, "删除成功", true);
    }

    @GetMapping("/to-table-list")
    public String toTableList(Model model) throws IOException {
        return "/views/db/tables_list";
    }

    @GetMapping("/table-list")
    @ResponseBody
    public JSONObject tableList(Long id) throws IOException {
        List<TableInfo> tableList = null;
        try {
            DbConfig dbConfig = dbConfigDao.getOne(id);
            tableList = tableInfoService.getAllTables(dbConfig);
        } catch (Exception e) {
            return respJson(500, "数据库链接失败", null);
        }
        return respJson(0, "succ", tableList);
    }

    @GetMapping("/to-column-list")
    public String toColumnList() {
        return "/views/db/column_list";
    }

    @GetMapping("/column-list")
    @ResponseBody
    public JSONObject columnList(String tableName, Long id) throws IOException {
        DbConfig dbConfig = dbConfigDao.getOne(id);
        TableInfo tableInfo = tableInfoService.getAllColumns(tableName, dbConfig);
        return respJson(0, "succ", tableInfo);
    }

    @GetMapping("/get-table-strategy")
    @ResponseBody
    public JSONObject getTableStrategy(String tableName, Long id) throws IOException {
        return respJson(0, "succ", tableStrategyConfigDao.findByDbIdAndTableName(id, tableName));
    }

    /**
     * 保存配置信息
     */
    @RequestMapping(value = "/columnsave", method = RequestMethod.POST)
    @ResponseBody
    public JSONObject save(Long id, String tableName, String comments, TableStrategyConfig tableStrategyConfig) {
        // 从请中取数据
        String[] remarks = request.getParameterValues("remarks[]");
        // 从数据 H2数据库中取出数据配置信息
        DbConfig dbConfig = dbConfigDao.getOne(id);
        TableInfo tableInfo = new TableInfo();
        tableInfo.setTableName(tableName);
        tableInfo.setComments(comments);
        List<ColumnInfo> listItem = new ArrayList<ColumnInfo>();
        for (String remark : remarks) {
            System.out.println(remark);
            String[] mark = remark.split("@");
            ColumnInfo item = new ColumnInfo();
            item.setColName(mark[0]);
            item.setColType(mark[1]);
            if (mark.length >= 3) {
                item.setComments(mark[2]);
            }
            if (mark.length >= 4) {
                item.setExtra(mark[3]);
            }
            if (mark.length >= 5) {
                item.setNullable("true".equalsIgnoreCase(mark[4]));
            }
            if (mark.length >= 6) {
                item.setDefaultValue(mark[5]);
            }
            listItem.add(item);
        }
        tableInfo.setListColumn(listItem);
        tableInfoService.saveTableComment(tableInfo, dbConfig);
        tableStrategyConfig.setDbId(id);
        tableStrategyConfig.setTableName(tableName);
        tableStrategyConfigDao.save(tableStrategyConfig);
        return respJson(0, "保存成功", true);
    }

    @GetMapping("/batch-generate")
    public String batchGenerate(String jsonStr, Long id, HttpServletResponse response) {
        TableStrategyConfig tableStrategyConfig = JSON.parseObject(jsonStr, TableStrategyConfig.class);
        if (tableStrategyConfig.getServicePackage() != null){
            tableStrategyConfig.setServiceCopierPackage(tableStrategyConfig.getServicePackage()+".mapstruct");
            tableStrategyConfig.setServiceCopierName("%sCopier");
        }

        DbConfig dbConfig = dbConfigDao.getOne(id);
        this.buildCodes(response, dbConfig, tableStrategyConfig);
        log.info("batchGenerate批量生成代码....");
        return null;
    }

    /**
     * 生成代码
     */
    @RequestMapping(value = "/generate", method = RequestMethod.GET)
    public String generate(String tableName, Long id, HttpServletResponse response) throws IOException {
        DbConfig dbConfig = dbConfigDao.getOne(id);
        TableStrategyConfig tableStrategyConfig = tableStrategyConfigDao.findByDbIdAndTableName(id, tableName);
        this.buildCodes(response, dbConfig, tableStrategyConfig);
        log.info(" generate 生成代码....");
        return null;
    }

    /**
     * 生成代码的核心逻辑
     *
     * @param response
     * @param dbConfig
     * @param tableStrategyConfig
     */
    private void buildCodes(HttpServletResponse response, DbConfig dbConfig, TableStrategyConfig tableStrategyConfig) {
        AutoGenerator mpg = new AutoGenerator();
        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        gc.setOutputDir(request.getSession().getServletContext().getRealPath("/") + "/WEB-INF/upload/" + request.getSession().getId());
        gc.setFileOverride(true);
        gc.setEnableCache(false);// XML 二级缓存
        gc.setBaseResultMap(true);// XML ResultMap
        gc.setBaseColumnList(false);// XML columList
        gc.setAuthor(tableStrategyConfig.getAuthor());
        gc.setEntityName(tableStrategyConfig.getEntityName());
        gc.setMapperName(tableStrategyConfig.getMapperName());
        gc.setXmlName(tableStrategyConfig.getXmlName());
        gc.setServiceName(tableStrategyConfig.getServiceName());
        gc.setServiceImplName(tableStrategyConfig.getServiceImplName());
        gc.setEntityToName(tableStrategyConfig.getEntityToName());
        gc.setEntityVoName(tableStrategyConfig.getEntityVoName());
        gc.setEntityDtoName(tableStrategyConfig.getEntityDtoName());
        gc.setEntityBoName(tableStrategyConfig.getEntityBoName());
        gc.setApiName(tableStrategyConfig.getApiName());
        gc.setApiImplName(tableStrategyConfig.getApiImplName());
        gc.setDomainPkg(true);
        gc.setServiceCopierName(tableStrategyConfig.getServiceCopierName());
        mpg.setGlobalConfig(gc);
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setDbType(dbConfig.getDriver().indexOf("mysql") > -1 ? DbType.MYSQL : DbType.H2);
        dsc.setDriverName(dbConfig.getDriver());
        dsc.setUsername(dbConfig.getUsername());
        dsc.setPassword(dbConfig.getPassword());
        dsc.setUrl(dbConfig.getUrl());
        dsc.setTypeConvert(new MySqlTypeConvertExt()); //dateTime ---> OFFSET_DATE_TIME
        mpg.setDataSource(dsc);
        StrategyConfig strategy = new StrategyConfig();
        // 前缀
        log.info("前缀:{}", tableStrategyConfig.getPrefix());
        if (!StringUtils.isEmpty(tableStrategyConfig.getPrefix())) {
            strategy.setTablePrefix(tableStrategyConfig.getPrefix());
        }
        log.info("需要生成的表:{}", JSON.toJSONString(tableStrategyConfig.getTableName()));
        strategy.setInclude(tableStrategyConfig.getTableName().split(",")); // 需要生成的表
        // 字段名生成策略
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        mpg.setStrategy(strategy);
        // 包配置
        PackageConfig packageConfig = handlerPackageConfig(tableStrategyConfig);
        mpg.setPackageInfo(packageConfig);
        // 注入自定义配置，可以在 VM 中使用 cfg.abc 设置的值
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                Map<String, Object> map = new HashMap<String, Object>();
                map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-mp");
                map.put("entityLombokModel", true);
                map.put("restControllerStyle", true);
                map.put("entityColumnConstant", true);
                map.put("swagger2", true);
                this.setMap(map);
            }
        };
        mpg.setCfg(cfg);
        // 自定义模板配置，可以 copy 源码 mybatis-plus/src/main/resources/template 下面内容修改，
        // 放置自己项目的 src/main/resources/template 目录下, 默认名称一下可以不配置，也可以自定义模板名称
        TemplateConfig tc = new TemplateConfig();
        tc.setController("/templates/generate-template/controller.java");
        tc.setEntity("/templates/generate-template/entity.java");
        tc.setMapper("/templates/generate-template/mapper.java");
        tc.setXml("/templates/generate-template/mapper.xml");
        tc.setService("/templates/generate-template/service.java");
        tc.setServiceImpl("/templates/generate-template/serviceImpl.java");
        tc.setEntityTo("/templates/generate-template/entityTo.java");
        tc.setEntityVo("/templates/generate-template/entityVo.java");
        tc.setEntityDto("/templates/generate-template/entitydto.java");
        tc.setEntityBo("/templates/generate-template/entitybo.java");
        tc.setApi("/templates/generate-template/api.java");
        tc.setApiImpl("/templates/generate-template/apiImpl.java");
        tc.setServiceCopier("/templates/generate-template/serviceCopier.java");
        mpg.setTemplate(tc);
        // 执行生成
        mpg.execute();
        // 打印注入设置
        log.info("执行的参数:{}", JSON.toJSONString(mpg.getPackageInfo()));
        //打包下载
        response.setContentType("APPLICATION/OCTET-STREAM");
        response.setHeader("Content-Disposition", "attachment; filename=src.zip");
        try {
            ZipFileUtils zip = new ZipFileUtils();
            ZipOutputStream zos = new ZipOutputStream(response.getOutputStream());
            String fileName = request.getSession().getServletContext().getRealPath("/") + "/WEB-INF/upload/" + request.getSession().getId();
            File ff = new File(fileName);
            if (!ff.exists()) {
                ff.mkdirs();
            }
            zip.zip(ff, zos, "");
            zos.flush();
            zos.close();
            //删除目录
            FileUtils.DeleteFolder(request.getSession().getServletContext().getRealPath("/") + "/WEB-INF/upload/" + request.getSession().getId());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public PackageConfig handlerPackageConfig(TableStrategyConfig tableStrategyConfig) {
        PackageConfig pc = new PackageConfig();
        // do 在这自定义包路径.
        pc.setParent("com");
        pc.setModuleName(tableStrategyConfig.getModelName());

        pc.setService(tableStrategyConfig.getServicePackage());
        pc.setServiceImpl(tableStrategyConfig.getServiceImplPackage());

        pc.setController(tableStrategyConfig.getControllerPackage());
//        pc.setEntityTo(tableStrategyConfig.getEntityToPackage());
		String tableNameStr = tableStrategyConfig.getTableName();
        String tableName = Arrays.asList(tableNameStr.split(",")).get(0);
        String table = NamingStrategy.camelToLowerCase(tableName);
        if (tableStrategyConfig.getChecked().equals("true") ) {
            // 需要表名称 开始组装表信息.
            String entityPackage = tableStrategyConfig.getEntityPackage().replace("^t^", StringPool.DOT + table );
            pc.setEntity(entityPackage);
            String entityDtoPackage = tableStrategyConfig.getEntityDtoPackage().replace("^t^", StringPool.DOT + table);
            System.out.println(" entityDtoPackage--->:"+entityDtoPackage);
            pc.setEntityDto(entityDtoPackage);
            String mapperPackage = tableStrategyConfig.getMapperPackage().replace("^t^", StringPool.DOT + table + StringPool.DOT);
            pc.setMapper(mapperPackage);
            pc.setXml(tableStrategyConfig.getXmlPackage().replace("^t^", StringPool.DOT + table));
            pc.setApi(tableStrategyConfig.getApiPackage()+StringPool.DOT+table);
            pc.setApiImpl( tableStrategyConfig.getApiPackage()+StringPool.DOT+table+StringPool.DOT+"impl");
            pc.setEntityVo(tableStrategyConfig.getApiPackage()+StringPool.DOT+table+StringPool.DOT+"vo");
            pc.setController(tableStrategyConfig.getControllerPackage()+StringPool.DOT+table);
			pc.setService(tableStrategyConfig.getServicePackage()+StringPool.DOT+table);
			pc.setServiceImpl(tableStrategyConfig.getServicePackage()+StringPool.DOT+table+StringPool.DOT+"impl");
            pc.setEntityBo(tableStrategyConfig.getServicePackage()+StringPool.DOT+table+StringPool.DOT+"bo");
            pc.setServiceCopier(tableStrategyConfig.getServicePackage()+StringPool.DOT+table+StringPool.DOT+"mapstruct");
        }else {
			String entityPackage = tableStrategyConfig.getEntityPackage()+ StringPool.DOT;
			pc.setEntity(entityPackage);
			String mapperPackage = tableStrategyConfig.getMapperPackage()+ StringPool.DOT;
			pc.setMapper(mapperPackage);
			pc.setXml(tableStrategyConfig.getXmlPackage()+ StringPool.DOT);
			pc.setApi(tableStrategyConfig.getApiPackage());
			pc.setApiImpl( tableStrategyConfig.getApiPackage()+StringPool.DOT+"impl");
			pc.setController(tableStrategyConfig.getControllerPackage());
			pc.setService(tableStrategyConfig.getServicePackage());
			pc.setServiceImpl(tableStrategyConfig.getServicePackage()+StringPool.DOT+"impl");
		}
        return pc;

    }


}

